﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace GpCommon.Helpers
{
    public class MouseHook
    {
        private Point point;
        private Point Point
        {
            get { return point; }
            set
            {
                if (point != value)
                {
                    point = value;
                    //if (MouseMoveEvent != null)
                    //{
                    //    var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
                    //    MouseMoveEvent(this, e);
                    //}
                }
            }
        }
        private int hHook;
        private static int hMouseHook = 0;
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        public const int WH_MOUSE_LL = 14;
        public Win32Helper.HookProc hProc;
        public MouseHook()
        {
            this.Point = new Point();
        }
        public int SetHook()
        {
            hProc = new Win32Helper.HookProc(MouseHookProc);
            hHook = Win32Helper.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
            return hHook;
        }
        public void UnHook()
        {
            Win32Helper.UnhookWindowsHookEx(hHook);
        }
        private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
        {
            Win32Helper.MouseHookStruct MyMouseHookStruct = (Win32Helper.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Helper.MouseHookStruct));
            if (nCode < 0)
            {
                return Win32Helper.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
            else
            {
                MouseButton button = MouseButton.Left;
                int clickCount = 0;
                switch ((Int32)wParam)
                {
                    //case WM_LBUTTONDOWN:
                    //    button = MouseButton.Left;
                    //    clickCount = 1;
                    //    MouseDownEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    //case WM_RBUTTONDOWN:
                    //    button = MouseButton.Right;
                    //    clickCount = 1;
                    //    MouseDownEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    //case WM_MBUTTONDOWN:
                    //    button = MouseButton.Middle;
                    //    clickCount = 1;
                    //    MouseDownEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    //case WM_LBUTTONUP:
                    //    button = MouseButton.Left;
                    //    clickCount = 1;
                    //    MouseUpEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    //case WM_RBUTTONUP:
                    //    button = MouseButton.Right;
                    //    clickCount = 1;
                    //    MouseUpEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    //case WM_MBUTTONUP:
                    //    button = MouseButton.Middle;
                    //    clickCount = 1;
                    //    MouseUpEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                    //    break;
                    case WM_MOUSEMOVE:
                        MouseMoveEvent(this, new MyMouseEventArgs(button, clickCount, point.X, point.Y));
                        break;
                }

                this.Point = new Point(MyMouseHookStruct.pt.X, MyMouseHookStruct.pt.Y);
                return Win32Helper.CallNextHookEx(hHook, nCode, wParam, lParam);
            }
        }

        public delegate void MouseMoveHandler(object sender, MyMouseEventArgs e);
        public event MouseMoveHandler MouseMoveEvent;

        public delegate void MouseClickHandler(object sender, MyMouseEventArgs e);
        public event MouseClickHandler MouseClickEvent;

        public delegate void MouseDownHandler(object sender, MyMouseEventArgs e);
        public event MouseDownHandler MouseDownEvent;

        public delegate void MouseUpHandler(object sender, MyMouseEventArgs e);
        public event MouseUpHandler MouseUpEvent;

        public class MyMouseEventArgs
        {
            public MouseButton MouseButton { get; set; }
            public int ClickCount { get; set; }
            public double X { get; set; }
            public double Y { get; set; }

            public MyMouseEventArgs(MouseButton button, int clickCount, double x, double y)
            {
                this.MouseButton = button;
                this.ClickCount = clickCount;
                this.X = x;
                this.Y = y;
            }
        }
    }
}
